-- Jednostka centralna

library IEEE;
use IEEE.Std_Logic_1164.all;
use IEEE.Std_Logic_Arith.all;
use work.constants.all;

entity CU1 is
  generic (delay : time := 5 ns);
  port (CLOCK, RESET            : in std_logic;
        INSTR, ADRARG1, ADRARG2 : in std_logic_vector(1 downto 0);
        ARG1, ARG2              : in std_logic_vector(3 downto 0);
        CU_GA                   : out std_logic_vector(2 downto 0);
        CU_ALU_INSTR, CU_ERROR  : out std_logic_vector(1 downto 0);
        CU_ROM_LAE, CU_ROM_R, CU_ROM_IE, CU_ROM_OE : out std_logic;
        CU_PC_INCR, CU_PC_RESET, CU_RI_LAE, CU_RN_LAE, CU_DE_DECODE : out std_logic;
        CU_RAM_LAE, CU_RAM_IE1, CU_RAM_IE2, CU_RAM_OE1, CU_RAM_OE2, CU_RAM_R, CU_RAM_W : out std_logic;
        CU_REGX_IE, CU_REGY_IE, CU_ALU_START : out std_logic);
end entity CU1;

architecture CU1_arch of CU1 is
begin
  process(CLOCK, RESET)
    variable state : integer := 0;
  begin
    if(RESET = '0') then
      state := 0;
      CU_ROM_OE <= '1';
      CU_RAM_OE1 <= '1';
      CU_RAM_OE2 <= '1';
      CU_RAM_IE1 <= '1';
      CU_RAM_IE2 <= '1';
      CU_ALU_START <= '1';
      CU_PC_RESET <= '0';
      CU_ERROR <= NO_ERROR;
    elsif(rising_edge(CLOCK)) then
      case state is
        when 0 =>
          CU_PC_RESET <= '1';
          CU_ALU_START <= '1';
          CU_RAM_OE1 <= '1';
          CU_RAM_W <= '1';
          CU_DE_DECODE <= '1';
           
          CU_GA <= GA_PC;
          CU_ROM_LAE <= '0';
          state := 1;
        when 1 =>
          CU_ROM_LAE <= '1';
          
          CU_PC_INCR <= '0';
          CU_ROM_R <= '0';
          CU_ROM_IE <= '0';
          state := 2;
        when 2 =>
          CU_PC_INCR <= '1';
          CU_ROM_R <= '1';
          CU_ROM_IE <= '1';
         
          CU_ROM_OE <= '0';
          CU_RI_LAE <= '0';
          CU_RN_LAE <= '0';
          state := 3;
        when 3 => 
          CU_ROM_OE <= '1';
          CU_RI_LAE <= '1';
          CU_RN_LAE <= '1';
          
          CU_DE_DECODE <= '0';
          state := 4;
        when 4 => 
          case INSTR is
            when CMP => state := 5;
            when MOV => state := 8;
            when others =>
              CU_ERROR <= ERR_BAD_INSTR;
              state := 14;
          end case;
          if (conv_integer(unsigned(ARG1)) > 12) then
            CU_ERROR <= ERR_OUT_OF_MEM; 
            state := 14;
          end if;
        when 5 => 
          CU_DE_DECODE <= '1';
          
          CU_GA <= GA_IMM;
          CU_RAM_LAE <= '0';
          state := 6;
        when 6 =>
          CU_RAM_LAE <= '1';
           
          CU_RAM_R <= '0';
          CU_RAM_IE1 <= '0';
          state := 7;
        when 7 => 
          CU_RAM_R <= '1';
          CU_RAM_IE1 <= '1';
          
          CU_RAM_OE2 <= '0';
          CU_REGX_IE <= '0';
          state := 8;
        when 8 => 
          CU_DE_DECODE <= '1';
          CU_RAM_OE2 <= '1';
          CU_REGX_IE <= '1';
          
          CU_GA <= GA_PC;
          CU_ROM_LAE <= '0';
        
          state := 9;
        when 9 => 
          CU_ROM_LAE <= '1';
          
          CU_PC_INCR <= '0';
          CU_ROM_R <= '0';
          CU_ROM_IE <= '0';
          
          case INSTR is
            when CMP => state := 10;
            when MOV => state := 12;
            when others => 
          end case;
        when 10 =>
          CU_PC_INCR <= '1';
          CU_ROM_R <= '1';
          CU_ROM_IE <= '1';
          
          CU_ROM_OE <= '0';
          CU_REGY_IE <= '0';
          state := 11; 
        when 11 =>
          CU_ROM_OE <= '1';
          CU_REGY_IE <= '1';
           
          CU_ALU_INSTR <= CMP;
          CU_ALU_START <= '0';
          state := 0;
        when 12 =>
          CU_PC_INCR <= '1';
          CU_ROM_R <= '1';
          CU_ROM_IE <= '1';
          
          CU_ROM_OE <= '0';
          CU_RAM_IE2 <= '0';
          CU_GA <= GA_IMM;
          CU_RAM_LAE <= '0';
          state := 13;
        when 13 =>
          CU_ROM_OE <= '1';
          CU_RAM_IE2 <= '1';
          CU_RAM_LAE <= '1';
          
          CU_RAM_OE1 <= '0';
          CU_RAM_W <= '0';
          state := 0;
        when 14 => 
          -- zapetlenie procesora w przypadku bledu
        when others =>
          CU_ERROR <= ERR_BAD_INSTR;
        end case;
    end if;
  end process;
end architecture CU1_arch;
